/**
 * Copyright (C) 2009 fgrilli <federico.grilli@gmail.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */
package info.magnolia.module.admininterface;

import info.magnolia.cms.servlets.MVCServletHandler;
import info.magnolia.cms.util.AlertUtil;
import info.magnolia.context.Context;
import info.magnolia.context.MgnlContext;

import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


/**
 * A simple command-based MVC handler which adds support for command validation. The
 * {@link ValidatableMVCHandler#validate(String, List)} method is called before executing a command. If the
 * <code>validate(..)</code> method returns <code>true</code>, the command execution is delegated to the
 * {@link MVCServletHandler#execute(String)} method. If it returns <code>false</code> the command will not be executed
 * and the {@link ValidatableMVCHandler#showErrors(List)} method will be called before showing the error view.
 * @author fgrilli
 * @version $Id: ValidatableMVCHandler.java 18 2009-04-19 11:44:18Z federico.grilli $
 */
public class ValidatableMVCHandler extends TemplatedMVCHandler
{

    /**
     * The default implementation of this method puts a {@link Context#ATTRIBUTE_EXCEPTION} attribute in the view
     * context. This attribute is a <code>String</code> holding an HTML fragment representing an unordered list of error
     * messages. This method is called automatically in case of {@link ValidatableMVCHandler#validate(String, List)}
     * returning <code>false</code>. You can override it to provide your own implementation for showing validation
     * errors to the end user.
     * @param errors - a list of {@link Exception} objects
     */
    protected void showErrors(List<Exception> errors)
    {
        StringBuilder sb = new StringBuilder("<ul>");
        for (Exception e : errors)
        {
            sb.append("<li>").append(e.getMessage()).append("</li>");
        }
        sb.append("</ul>");
        if (!AlertUtil.isExceptionSet())
            MgnlContext.getInstance().setAttribute(Context.ATTRIBUTE_EXCEPTION, sb.toString(), Context.LOCAL_SCOPE);
        if (!AlertUtil.isMessageSet())
            MgnlContext.getInstance().setAttribute(Context.ATTRIBUTE_MESSAGE, sb.toString(), Context.LOCAL_SCOPE);
    }

    /**
     * @param name
     * @param request
     * @param response
     */
    public ValidatableMVCHandler(String name, HttpServletRequest request, HttpServletResponse response)
    {
        super(name, request, response);
    }

    /**
     * This is the method to override in order to provide custom validation handling. The default implementation always
     * returns <code>true</code>.
     * @param commandName - String the name of the command which will be called if this method returns <code>true</code>
     * .
     * @param errors - List a list of {@link Exception} objects. The {@link Exception}s you'll add here are made
     * available to the {@link ValidatableMVCHandler#showErrors(List)} method.
     * @return <code>false</code> in case of validation errors, <code>true</code> otherwise.
     */
    public boolean validate(String commandName, List<Exception> errors)
    {
        return true;
    }

    @Override
    public final String execute(String commandName)
    {
        List<Exception> errors = new ArrayList<Exception>();
        if (!validate(commandName, errors))
        {
            log.warn("validate for command {} returned errors", commandName);
            showErrors(errors);
            return VIEW_ERROR;
        }
        return super.execute(commandName);
    }
}